/**
 * Xilinx PL/AXI-GPIO 驱动适配层头文件
 * 张勇 / 41204@qq.com
 *
 * 关于 AXI-GPIO
 * - 每个 AXI-GPIO 模块可能有 1~2 个 channel
 * - 每个 channel 可能有 1~32 个 pin
 * - 每个 AXI-GPIO 模块只有一条中断线(对应 GIC 的一个 IRQN)，由两个 channel 共享；
 * - 每个 AXI-GPIO 模块有一个全局的中断使能位
 * - 每个 channel 各有一个中断使能位、中断状态/清除位，由本 channel 内各个 pin 共享
 * - 每个 AXI-GPIO 模块的中断检测模块检测到任一 channel 的任一 pin 输入信号有变化时，会在 ip2intc_irpt 引脚输出一个 100 个周期左右的高电平脉冲信号
 * - 所以 GIC 检测 AXI-GPIO 中断时，只能采用上升沿触发
 */

#ifndef _GPIO_PL_H_
#define _GPIO_PL_H_

#include <stdint.h>
#include <stdbool.h>
#include "share/std_err.h"
#include "gpio.h"

#ifdef __cplusplus
extern "C" {
#endif

/// 端口配置
std_err_t XGPIO_Config(uint16_t devid, uint16_t chid, uint16_t pin, gpio_mode_t mode);
/// 设置输出电平
std_err_t XGPIO_SetLevel(uint16_t devid, uint16_t chid, uint16_t pin, uint8_t level);
/// 获取输入电平
uint8_t   XGPIO_GetLevel(uint16_t devid, uint16_t chid, uint16_t pin);
/// 双向输入
uint8_t   XGPIO_BidiIn(uint16_t devid, uint16_t chid, uint16_t pin);
/// 双向输出
std_err_t XGPIO_BidiOut(uint16_t devid, uint16_t chid, uint16_t pin, uint8_t level);

/// 配置中断
std_err_t XGPIO_EXTI_Config(uint16_t devid, uint16_t chid, uint16_t pin, uint32_t irqn, uint8_t priority, mcu_isr_t isr, void *cookie);
/// 使能/关闭中断
std_err_t XGPIO_EXTI_Enable(uint16_t devid, uint16_t chid, uint16_t pin, uint32_t irqn, bool enable);
/// 判断对应引脚是否产生中断
bool      XGPIO_EXTI_Flag(uint16_t devid, uint16_t chid, uint16_t pin);
/// 清除对应引脚中断标志位
std_err_t XGPIO_EXTI_Clear(uint16_t devid, uint16_t chid);
/// 手动触发指定通道的中断
std_err_t XGPIO_EXTI_TrigMannually(uint16_t devid, uint16_t chid);

/**
 * 定义命名的 APIs(基本的)
 */
#define XGPIO_DEFINE(NAME, DEVID, CHID, PIN, IRQN) \
	static inline std_err_t XGPIO_##NAME##_Config(gpio_mode_t mode)  { return XGPIO_Config(DEVID, CHID, PIN, mode); } \
	static inline int8_t    XGPIO_##NAME##_ReadIn(void)              { return XGPIO_GetLevel(DEVID, CHID, PIN); } \
	static inline std_err_t XGPIO_##NAME##_WriteOut(bool x)          { return XGPIO_SetLevel(DEVID, CHID, PIN, x); } \
	static inline uint8_t   XGPIO_##NAME##_ReadOut(void)             { return XGPIO_GetLevel(DEVID, CHID, PIN); } \
	static inline uint8_t   XGPIO_##NAME##_BidiIn(void)              { return XGPIO_BidiIn(DEVID, CHID, PIN); } \
	static inline std_err_t XGPIO_##NAME##_BidiOut(uint8_t x)        { return XGPIO_BidiOut(DEVID, CHID, PIN, x); } \
	static inline std_err_t XGPIO_##NAME##_Toggle(void)              { return XGPIO_SetLevel(DEVID, CHID, PIN, !XGPIO_GetLevel(DEVID, CHID, PIN)); } \
	static inline std_err_t XGPIO_##NAME##_EXTI_Config(uint8_t priority, mcu_isr_t isr, void *cookie) { return XGPIO_EXTI_Config(DEVID, CHID, PIN, IRQN, priority, isr, cookie); } \
	static inline std_err_t XGPIO_##NAME##_EXTI_Enable()             { return XGPIO_EXTI_Enable(DEVID, CHID, PIN, IRQN, true); } \
	static inline std_err_t XGPIO_##NAME##_EXTI_Disable()            { return XGPIO_EXTI_Enable(DEVID, CHID, PIN, IRQN, false); } \
	static inline std_err_t XGPIO_##NAME##_EXTI_Flag(void)           { return XGPIO_EXTI_Flag(DEVID, CHID, PIN); } \
	static inline std_err_t XGPIO_##NAME##_EXTI_Clear(void)          { return XGPIO_EXTI_Clear(DEVID, CHID); }

/**
 * 定义命名的 APIs(带极性的)
 */
#define XGPIO_DEFINE_POLARITY(NAME, DEVID, CHID, PIN, IRQN, ACTIVE_LEVEL) \
	XGPIO_DEFINE(NAME, DEVID, CHID, PIN, IRQN) \
	static inline uint8_t   XGPIO_##NAME##_Polarity(void)             { return ACTIVE_LEVEL; } \
	static inline std_err_t XGPIO_##NAME##_On(void)                   { return GPIO_##NAME##_Out(ACTIVE_LEVEL); } \
	static inline std_err_t XGPIO_##NAME##_Off(void)                  { return GPIO_##NAME##_Out(!ACTIVE_LEVEL); } \
	static inline std_err_t XGPIO_##NAME##_Switch(uint8_t on)         { return on ? GPIO_##NAME##_Out(ACTIVE_LEVEL) : GPIO_##NAME##_Out(!ACTIVE_LEVEL); } \
	static inline uint8_t   XGPIO_##NAME##_IsInOn(void)               { return (GPIO_##NAME##_ReadIn()  == ACTIVE_LEVEL); } \
	static inline uint8_t   XGPIO_##NAME##_IsInOff(void)              { return (GPIO_##NAME##_ReadIn()  != ACTIVE_LEVEL); } \
	static inline uint8_t   XGPIO_##NAME##_IsOutOn(void)              { return (GPIO_##NAME##_ReadOut() == ACTIVE_LEVEL); } \
	static inline uint8_t   XGPIO_##NAME##_IsOutOff(void)             { return (GPIO_##NAME##_ReadOut() != ACTIVE_LEVEL); }


#ifdef __cplusplus
}
#endif

#endif // _GPIO_PL_H_
